#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

const static int defaultcap = 5; // 这是队列的默认容量
template <class T>
class RingQueue
{
private:
  void P(sem_t &sem) // 等待，获取
  {
    sem_wait(&sem);
  }

  void V(sem_t &sem)
  {
    sem_post(&sem); // 释放资源
  }

  void Lock(pthread_mutex_t &mutex)
  {
    pthread_mutex_lock(&mutex);
  }
  void Unlock(pthread_mutex_t &mutex)
  {
    pthread_mutex_unlock(&mutex);
  }

public:
  RingQueue(int cap = defaultcap)
      : ringqueue_(cap), cap_(cap), c_step_(0), p_step_(0)
  {
    sem_init(&cdata_sem_, 0, 0);    // 初始化数据资源，因为一开始数据资源为空
    sem_init(&pspace_sem_, 0, cap); // 初始化空间资源，一开始空间资源是满的

    pthread_mutex_init(&c_mutex_, nullptr);
    pthread_mutex_init(&p_mutex_, nullptr); // 初始化两把锁
  }

  void Push(const T &in) // 生产
  {
    P(pspace_sem_); // 空间资源--
    Lock(p_mutex_);
    ringqueue_[p_step_] = in;
    // 位置后移，维持环形特征
    p_step_++;
    p_step_ %= cap_;
    Unlock(p_mutex_); // 释放锁
    V(cdata_sem_);    // 数据资源++
  }
  void Pop(T *out) // 消费
  {
    // 就是用out取出队列中的任务
    P(cdata_sem_); // 数据资源--
    Lock(c_mutex_);
    *out = ringqueue_[c_step_];
    // 位置后移，维持环形

    c_step_++;
    c_step_ %= cap_;
    Unlock(c_mutex_);

    V(pspace_sem_); // 空间资源++
  }

  ~RingQueue() // 析构函数，释放资源
  {
    sem_destroy(&cdata_sem_);
    sem_destroy(&pspace_sem_); // 信号量

    pthread_mutex_destroy(&c_mutex_);
    pthread_mutex_destroy(&p_mutex_); // 锁
  }
  // 属性
private:
  std::vector<T> ringqueue_; // 用数组模拟循环队列
  int cap_;                  // 容量

  int p_step_;       // 生产者下标
  int c_step_;       // 消费者下标
                     // 下面是条件变量
  sem_t cdata_sem_;  // 消费者关注的数据资源
  sem_t pspace_sem_; // 生产者关注的空间资源

  pthread_mutex_t c_mutex_;
  pthread_mutex_t p_mutex_; // 两把锁
};